#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <poll.h>
#include <linux/input.h>
#include <aio.h>
#include <signal.h>

#include "vser.h"

// 用于写的异步IO控制块
void aiow_completion_handler(sigval_t sigval)
{
    int ret;
    struct aiocb *req;
    ret = (struct aiocb*)sigval.sival_ptr;
    if (aio_error(req) == 0) {  // 获取错误码
        ret = aio_return(req);  // 获取写操作的实际返回值
        printf("aio write %d bytes\n", ret);
    }
}

// 用于读的异步IO控制块
void aior_completion_handler(sigval_t sigval)
{
    int ret;
    struct aiocb *req;
    ret = (struct aiocb *) sigval.sival_ptr;
    if (aio_error(req) == 0) {  // 获取错误码
        ret = aio_return(req);  // 获取读操作的实际返回值
        if (ret) {
            printf("aio read: %s\n", (char *)req->aio_buf);
        }
    }
    return;
}

int main(int argc, char* argv[])
{
    int ret;
    int fd;
    struct aiocb aiow, aior;

    // 打开第一个设备
    fd = open("/dev/vser0", O_RDWR);
    if (fd == -1) {
        goto fail;
    }

    memset(&aiow, 0, sizeof(aiow));
    memset(&aior, 0, sizeof(aior));

    // 初始化异步IO控制块
    aiow.aio_fildes = fd;  // 指定文件描述符
    aiow.aio_buf = malloc(32);  // 指定缓冲区
    strcpy((char*)aiow.aio_buf, "aio test");
    aiow.aio_nbytes = strlen((char *)aiow.aio_buf) +1;  // 读写的字节数
    aiow.aio_offset = 0;
    aiow.aio_sigevent.sigev_notify = SIGEV_THREAD;
    aiow.aio_sigevent.sigev_notify_function = aiow_completion_handler;  // 异步IO完成后的回调函数
    aiow.aio_sigevent.sigev_notify_attributes = NULL;
    aiow.aio_sigevent.sigev_value.__sival_ptr = &aiow;

    aior.aio_fildes = fd;
    aior.aio_buf = malloc(32);
    aior.aio_nbytes = 32;
    aior.aio_offset = 0;
    aior.aio_sigevent.sigev_notify = SIGEV_THREAD;
    aior.aio_sigevent.sigev_notify_function = aior_completion_handler;
    aior.aio_sigevent.sigev_notify_attributes = NULL;
    aior.aio_sigevent.sigev_value.__sival_ptr = &aior;

    while (1) {
        // 异步操作，会立即返回
        if (aio_write(&aiow) == -1) {
            goto fail;
        }
        if (aio_read(&aior) == -1) {
            goto fail;
        }
        sleep(1);
    }

fail:
    perror("aio test");
    exit(EXIT_FAILURE);
}